/**
 * 
 */
package edu.cornell.cs.lsi.projone.service;

import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.List;
import java.util.Random;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.LogFactoryImpl;

import edu.cornell.cs.lsi.projone.common.LSIConstants;
import edu.cornell.cs.lsi.projone.common.LSIException;
import edu.cornell.cs.lsi.projone.common.util.AppUtil;
import edu.cornell.cs.lsi.projone.model.ServerData;

/**
 * @author poornima
 * 
 */
public class GroupMemberManager {

	private final static Log LOGGER = LogFactoryImpl
			.getLog(GroupMemberManager.class);

	private static ServerDataManager serverDataMgr;
	private static DBManager dbMgr;
	private long probeTime;
	private static String ipAddr = "";
	private static int port;

	public GroupMemberManager() {

		// if (serverDataMgr != null) {
		init();
		// }

	}

	public void init() {
		LOGGER.info("init(): Group member manager starts...");
		if (serverDataMgr == null) {
			serverDataMgr = ServerDataManager.getInstance();
		}
		if (dbMgr == null) {
			dbMgr = new DBManager();
		}

		probeTime = 5000;

		if (ipAddr == null || StringUtils.isEmpty(ipAddr)) {
			try {
				ipAddr = InetAddress.getLocalHost().getHostAddress();
			} catch (UnknownHostException exp) {
				LOGGER.error("Unknown Host exception");
				exp.printStackTrace();
			}
		}
		LOGGER.info("GROUP MANAGER: IP " + ipAddr);

		if (port <= 0) {
			port = AppUtil.getPort();
		}
		LOGGER.info("GROUP MANAGER: port " + port);
	}

	public void scanGroup() throws LSIException {
		LOGGER.info("scanGroup(): starts...");
		List<ServerData> serverList = dbMgr.getAllServerData();
		boolean isAlive = false;
		boolean isPresent = false;
		// the server list is empty..
		if (serverList == null || serverList.isEmpty()) {
			ServerData data = new ServerData();
			data.setIpHostName(ipAddr);
			data.setPort(port);
			dbMgr.saveServerData(data);
			return;
		}
		for (ServerData serverInfo : serverList) {
			LOGGER.info("scanGroup():   IP" + serverInfo.getIpHostName());
			LOGGER.info("scanGroup():   Port" + serverInfo.getPort());
			if (serverInfo.getIpHostName().equals(ipAddr)
					&& serverInfo.getPort() == port) {
				isPresent = true;
				break;
			}
		}
		Random generator = new Random();
		int randomNum = generator.nextInt(serverList.size());
		ServerData serverInfo = serverList.get(randomNum);

		if (!serverInfo.getIpHostName().equals(ipAddr)
				&& serverInfo.getPort() != port) {
			StringBuffer result = new StringBuffer("");
			int callId = AppUtil.getCallID();
			result.append(callId);
			result.append(LSIConstants.PACKET_DATA_DELIMITER);
			result.append(LSIConstants.PROBE_MESSG_TYPE);
			try {
				UDPService.sendPacket(result.toString(), serverInfo);
			} catch (LSIException exp) {
				isAlive = false;
			} catch (UnknownHostException exp) {
				isAlive = false;
			}
			LOGGER.info("========================= after sending..");
			String response;
			while (true) {
				try {
					response = UDPService.recvPacket(port, (int) probeTime);
					if (response != null && StringUtils.isEmpty(response)) {
						String messgTokens[] = response
								.split(LSIConstants.PACKET_DATA_DELIMITER);
						if (messgTokens != null && messgTokens.length > 0) {
							if (LSIConstants.ALIVE_MESSG_TYPE
									.equals(messgTokens[1])
									&& callId == Integer
											.parseInt(messgTokens[0])) {
								// ALive message
								isAlive = true;
								break;
							}
						}
					}
				} catch (SocketTimeoutException exp) {
					LOGGER.info("========================= socket ---");
					isAlive = false;
					LOGGER.error("Socket timeout exception.");
					break;
				} catch (LSIException exp) {
					LOGGER.info("========================= LSI exception");
					isAlive = false;
					LOGGER.error("LSIexception.");
					break;
				}
			}
			if (!isAlive) {
				LOGGER.warn("The server is not present. "
						+ serverList.get(randomNum));
				// remove the dead node from the list and then save to database.
				LOGGER.info("========================= removing the code");
				serverList.remove(randomNum);
				dbMgr.saveServerData(serverList);
			}
		}

		if (!isPresent) {
			ServerData serverData = new ServerData();

			serverData.setPort(port);
			serverData.setIpHostName(ipAddr);
			serverList.add(serverData);
			dbMgr.saveServerData(serverList);
		}
		// if (!isAlive || !isPresent) {
		// LOGGER.info("========================= before saving");
		// dbMgr.saveServerData(serverList);
		// serverDataMgr.getInstance().addServerInfo(serverList);
		// }
		// serverDataMgr.getInstance().
		serverDataMgr.getInstance().addServerInfo(serverList);
		LOGGER.info("scanGroup(): ends... before ending... server size"
				+ serverDataMgr.getInstance().getServerDataList());
	}

	public Collection<ServerData> getServerList() {
		LOGGER.info("GRP member manager Server list size :-------------------"
				+ serverDataMgr.getServerDataList());
		return serverDataMgr.getServerDataList();
	}
}